JS 为什么新增 Set 与 Map
提示
Map / Set 是为弥补 普通对象与数组 在「键类型、唯一性、有序性、性能」上的短板;不必机械地把 Map 当「替代 Object」、Set 当「替代 Array」——前者是映射与字典场景,后者是集合与去重场景,语义更清晰。
要点速览
shell
ES6 之前常驻结构主要是「对象(键值)」与「数组(有序列表)」,各有局限。
# Map —— 为何要它
对象的键在非 Symbol 时被当作字符串语义处理;枚举顺序与原型链也会增加心智负担;
Map:任意类型作键(含对象)、插入顺序稳定、自带 size、无「继承来的默认键」,适合词典与缓存索引。
# Set —— 为何要它
数组允许重复元素,大批量下去重(Array → Set)成本高;仅靠 includes 判断是否「出现过」近似 O(n);
Set:值唯一、has 近似 O(1),适合标签集合、黑名单、瞬时去重。
# 心智模型
业务配置、JSON 形态的普通数据:仍常用 Object;
需要「非标量键」「稳定迭代顺序」「频繁增删键」:优先考虑 Map;
需要「不允许重复」「集合运算」、且要**反复判断成员是否存在**:优先考虑 Set;
仍要按索引随机访问序列:仍旧是 Array。相较 Object / Array 的补充对照(承接《优化》篇详解)
Map 相对 Object
shell
键类型:对象键实际是 String / Symbol(其它类型会先转字符串);Map 可为任意引用或原始值。
有序性:Object 在现代引擎下键顺序有一套规则但并非为「词典」建模;Map 始终按插入序迭代。
体量:巨型键集合下频繁删改 Map 常见实现往往更友好;小配置 Object 仍足够简单。Set 相对 Array
shell
唯一性:Set 自动维护不重复;数组需逻辑或二次结构保证。
查找:大范围下 has 优于反复 includes/sccan。
交集 / 差集:用 Set 表达集合运算往往更直白(也可转回数组输出)。对照表(速记)
shell
结构 本质 键 / 值类型 是否允许重复 键是否有序 长度获取 查询性能 是否继承原型 迭代方式
Object 普通业务对象 键只能:字符串/Symbol 值可重复,键唯一 ES6 后有序 Object.keys().length 一般 有原型污染风险 for/in
Map 键值映射 键任意类型 值可重复,键唯一 插入有序 .size O(1) 哈希快 纯净无原型 for/of、forEach
Array 有序序列 下标 元素可任意重复 下标有序 .length、includes O(n) 线性扫描为主 — for/of、forEach
Set 唯一集合 仅存值 元素唯一 插入有序 .size、has ~O(1) 哈希快 纯净无原型 for/of、forEach典型选型
对象(Object):固定 schema、键均为字符串的配置、与 JSON 互转频繁的 DTO。 Map:键可能为 DOM 节点/对象、cache.set(obj, derived)、需按插入顺序稳定遍历。 数组(Array):需要排序、splice、按索引读写、或与后端列表一一对应的序列语义。 Set:用户 ID、标签枚举、爬虫 URL 判重、[...new Set(arr)] 一次性去重。
注意
- Set 与 Map 都按插入顺序迭代(规范要求)。
- Set 没有「键」只有「值」;若需要键值对请用 Map。
